00001 // ------------------------------------------------------------- 00002 /* 00003 * Copyright (c) 2013 Battelle Memorial Institute 00004 * Licensed under modified BSD License. A copy of this license can be found 00005 * in the LICENSE file in the top level directory of this distribution. 00006 */ 00007 // ------------------------------------------------------------- 00008 // ------------------------------------------------------------- 00009 /** 00010 * @file pf_helper.cpp 00011 * @author William A. Perkins 00012 * @date 2014-11-25 07:12:27 d3g096 00013 * 00014 * @brief 00015 * 00016 * 00017 */ 00018 // ------------------------------------------------------------- 00019 00020 #include <iostream> 00021 #include <ga++.h> 00022 00023 #include "pf_factory_module.hpp" 00024 00025 00026 namespace gridpack { 00027 namespace powerflow { 00028 00029 /** 00030 * A helper functor for the powerflow solver. 00031 * This is a utility functor that provides functions that build the 00032 * Jacobian and RHS from the network. 00033 * 00034 */ 00035 struct PFSolverHelper 00036 : private utility::Uncopyable 00037 { 00038 00039 // The powerflow factory 00040 boost::shared_ptr<PFFactoryModule> p_factory; 00041 00042 // The powerflow network controlled by ::p_factory 00043 boost::shared_ptr<PFNetwork> p_network; 00044 00045 // A place to build/store the Jacobian 00046 boost::shared_ptr<math::RealMatrix> J; 00047 00048 // The network state estimate from previous solver iteration 00049 /** 00050 * See ::update() for why this is necessary. 00051 * 00052 */ 00053 boost::shared_ptr<math::RealVector> Xold; 00054 00055 /** 00056 * The current network state estimate. 00057 * This vector provides a space for the nonlinear solve to store the 00058 * current solution estimate. It should be filled with the initial 00059 * condition, handed to the nonlinear solver, and not changed 00060 * afterward. 00061 * 00062 */ 00063 boost::shared_ptr<math::RealVector> X; 00064 00065 /** 00066 * The difference between the current and previous estimate. 00067 * See ::update() for why this is necessary. 00068 * 00069 */ 00070 boost::shared_ptr<math::RealVector> Xdelta; 00071 00072 /** 00073 * Constructor 00074 * The current network state is gathered from the network. 00075 * @param factory powerflow factory 00076 * @param network network controlled by @c factory 00077 * @return 00078 */ 00079 PFSolverHelper(boost::shared_ptr<PFFactoryModule> factory, 00080 boost::shared_ptr<PFNetwork> network) 00081 : p_factory(factory), p_network(network), Xold(), Xdelta() 00082 { 00083 p_factory->setMode(State); 00084 mapper::BusVectorMap<PFNetwork> vMap(p_network); 00085 Xold = vMap.mapToRealVector(); 00086 // Xold->print(); 00087 X.reset(Xold->clone()); 00088 Xdelta.reset(Xold->clone()); 00089 Xdelta->zero(); 00090 p_factory->setMode(Jacobian); 00091 mapper::FullMatrixMap<PFNetwork> jMap(p_network); 00092 J = jMap.mapToRealMatrix(); 00093 } 00094 00095 /** 00096 * Push the current estimated state back onto the network. 00097 * The network state (voltage, phase) is updated with the current 00098 * estimate from the nonlinear solver. 00099 * 00100 * FIXME: The problem here is that ...::mapToBus expects the 00101 * @e CHANGE (old - current)? in state variables. IMHO, there should 00102 * be a way to set the state variables directly. The solver should 00103 * be responsible for making the @e entire estimate. 00104 * 00105 * @param Xcur current state estimate from the solver 00106 */ 00107 void 00108 update(const math::RealVector& Xcur) 00109 { 00110 00111 Xdelta->equate(Xcur); 00112 Xdelta->scale(-1.0); 00113 Xdelta->add(*Xold); 00114 double snorm(Xdelta->norm2()); 00115 if (Xdelta->processor_rank() == 0) { 00116 std::cout << "PFSolverHelper::update(): solution residual: " << snorm << std::endl; 00117 } 00118 00119 // Xdelta->print(); 00120 p_factory->setMode(RHS); 00121 mapper::BusVectorMap<PFNetwork> vMap(p_network); 00122 vMap.mapToBus(Xdelta); 00123 Xold->equate(Xcur); 00124 00125 // Exchange data between ghost buses (I don't think we need to exchange data 00126 // between branches) 00127 p_network->updateBuses(); 00128 00129 } 00130 00131 /** 00132 * Build the Jacobian Matrix. 00133 * This is called by the nonlinear solver each iteration to build 00134 * the Jacobian from the current network state. 00135 * 00136 * @param Xcur current state estimate 00137 * @param J Jacobian 00138 */ 00139 void 00140 operator() (const math::RealVector& Xcur, math::RealMatrix& theJ) 00141 { 00142 // In both the Netwon-Raphson and PETSc nonlinear solver (some 00143 // methods) implementations, the RHS function builder is called 00144 // before this, so we may be able to count on the current solution 00145 // being on the netork when here. 00146 00147 // X.print(); 00148 // update(Xcur); 00149 00150 // Set to build Jacobian 00151 printf("Got to operator J\n"); 00152 p_factory->setMode(Jacobian); 00153 mapper::FullMatrixMap<PFNetwork> jMap(p_network); 00154 00155 // build the Jacobian 00156 jMap.mapToRealMatrix(theJ); 00157 } 00158 00159 /** 00160 * Build the RHS function vector. 00161 * This is called by the nonlinear solver each iteration to build 00162 * the RHS vector from the current network state. This is also 00163 * responsible for updating the network state with the current 00164 * solution estimate, which assumes that it is called only once per 00165 * solver iteration. This may not be true if certain methods are 00166 * used or if a finite difference Jacobian is computed by the 00167 * solver. 00168 * 00169 * @param Xcur current state estimate 00170 * @param PQ computed RHS vector 00171 */ 00172 void 00173 operator() (const math::RealVector& Xcur, math::RealVector& PQ) 00174 { 00175 // In both the Netwon-Raphson and PETSc nonlinear solver 00176 // implementations, this is called before the Jacobian builder, so 00177 // we may only need to map the solution back on to the network here. 00178 00179 // X.print(); 00180 update(Xcur); 00181 00182 // set to build RHS vector 00183 p_factory->setMode(RHS); 00184 mapper::BusVectorMap<PFNetwork> vMap(p_network); 00185 00186 // build the RHS vector 00187 vMap.mapToRealVector(PQ); 00188 printf("norm of PQ: %f\n",PQ.norm2()); 00189 } 00190 }; 00191 } 00192 }